package com.ibeeking.found.org.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ibeeking.found.common.entity.EmployeeDTO;
import com.ibeeking.found.common.entity.SimpleEmployeeDTO;
import com.ibeeking.found.common.entity.query.EmployeeFeignQuery;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.SexEnum;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.org.b.rest.service.IEmployeeService;
import com.ibeeking.found.org.service.common.dos.DepartmentDO;
import com.ibeeking.found.org.service.common.dos.EmployeeDO;
import com.ibeeking.found.org.service.common.dos.OrgPositionDO;
import com.ibeeking.found.org.service.common.enums.EmployeeStatusEnum;
import com.ibeeking.found.org.service.common.param.EmployeeParam;
import com.ibeeking.found.org.service.common.query.EmployeePageQuery;
import com.ibeeking.found.org.service.common.query.EmployeeQuery;
import com.ibeeking.found.org.service.common.vo.DepartmentTreeVO;
import com.ibeeking.found.org.service.common.vo.EmployeeStatusVO;
import com.ibeeking.found.org.service.common.vo.EmployeeVO;
import com.ibeeking.found.org.service.mapper.DepartmentMapper;
import com.ibeeking.found.org.service.mapper.EmployeeMapper;
import com.ibeeking.found.org.service.mapper.OrgPositionMapper;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.ParamCheckUtils;
import com.ibeeking.nematos.utils.data.TreeFastUtils;
import com.ibeeking.nematos.utils.json.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName EmployeeServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-01-29 14:48
 **/
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, EmployeeDO> implements IEmployeeService {

    @Resource
    private EmployeeMapper employeeMapper;

    @Resource
    private DepartmentMapper departmentMapper;

    @Resource
    private OrgPositionMapper orgPositionMapper;

    @Override
    public List<EmployeeVO> list(EmployeeQuery query) {
        if(query.getDepartmentId() != null){
            List<Long> departmentIds = getAllDepartmentIdsByPId(query.getDepartmentId());
            query.setDepartmentIds(departmentIds);
        }
        List<EmployeeVO> resultVOS = new ArrayList<>();
        List<EmployeeDO> entityDOS = employeeMapper.selectList(new LambdaQueryWrapper<EmployeeDO>()
                .eq(query.getId()!=null ,EmployeeDO::getId, query.getId())
                .in(Collections3.isNotEmpty(query.getDepartmentIds()),EmployeeDO::getDepartmentId,query.getDepartmentIds())
                .eq(query.getPositionId()!=null ,EmployeeDO::getPositionId, query.getPositionId())
                .eq(query.getGender()!=null ,EmployeeDO::getGender, query.getGender())
                .eq(StringUtils.isNotEmpty(query.getCode()),EmployeeDO::getCode, query.getCode())
                .like(StringUtils.isNotEmpty(query.getName()),EmployeeDO::getName, query.getName())
                .eq(query.getStatus()!=null ,EmployeeDO::getStatus, query.getStatus())
                .orderByDesc(EmployeeDO::getCreateTime));
        if(Collections3.isNotEmpty(entityDOS)){
            List<DepartmentDO> departmentDOList = departmentMapper.selectList(new LambdaQueryWrapper<DepartmentDO>().eq(DepartmentDO::getPublishStatus,PublishStatusEnum.ENABLE.getValue()));
            Map<Long, String> departmentNameMaps = Collections3.isNotEmpty(departmentDOList)?departmentDOList.parallelStream().collect(Collectors.toMap(DepartmentDO::getId, DepartmentDO::getName, (o, n) -> o)):null;

            List<OrgPositionDO> orgPositionDOList = orgPositionMapper.selectList(new LambdaQueryWrapper<OrgPositionDO>().eq(OrgPositionDO::getPublishStatus,PublishStatusEnum.ENABLE.getValue()));
            Map<Long, String> orgPositionNameMaps = Collections3.isNotEmpty(orgPositionDOList)?orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getName, (o, n) -> o)):null;
            Map<Long, Long> orgPositionJobMaps = Collections3.isNotEmpty(orgPositionDOList)?orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getJobId, (o, n) -> o)):null;

            resultVOS = entityDOS.stream().map(s->{
                EmployeeVO entityVO = BeanUtil.convertBean(s, EmployeeVO.class);
                entityVO.setDepartmentName(departmentNameMaps!=null?departmentNameMaps.get(s.getDepartmentId()):"");
                entityVO.setPositionName(orgPositionNameMaps!=null?orgPositionNameMaps.get(s.getPositionId()):"");
                entityVO.setJobId(orgPositionJobMaps!=null?orgPositionJobMaps.get(s.getPositionId()):null);
                entityVO.setStatusDesc(EmployeeStatusEnum.getDescByCode(s.getStatus()));
                entityVO.setGenderDesc(SexEnum.getDescByCode(s.getGender()));
                return entityVO;
            }).collect(Collectors.toList());
        }
        return resultVOS;
    }

    @Override
    public Page<EmployeeVO> pageList(EmployeePageQuery pageQuery) {
        if(pageQuery.getDepartmentId() != null){
            List<Long> departmentIds = getAllDepartmentIdsByPId(pageQuery.getDepartmentId());
            pageQuery.setDepartmentIds(departmentIds);
        }
        LambdaQueryWrapper<EmployeeDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(pageQuery.getId() != null, EmployeeDO::getId, pageQuery.getId())
                .eq(pageQuery.getId()!=null ,EmployeeDO::getId, pageQuery.getId())
                .in(Collections3.isNotEmpty(pageQuery.getDepartmentIds()),EmployeeDO::getDepartmentId,pageQuery.getDepartmentIds())
                .eq(pageQuery.getPositionId()!=null ,EmployeeDO::getPositionId, pageQuery.getPositionId())
                .eq(pageQuery.getGender()!=null ,EmployeeDO::getGender, pageQuery.getGender())
                .eq(StringUtils.isNotEmpty(pageQuery.getCode()),EmployeeDO::getCode, pageQuery.getCode())
                .like(StringUtils.isNotEmpty(pageQuery.getName()),EmployeeDO::getName, pageQuery.getName())
                .eq(pageQuery.getStatus()!=null ,EmployeeDO::getStatus, pageQuery.getStatus())
                .orderByDesc(EmployeeDO::getCreateTime);

        Page<EmployeeDO> entityDOPages = employeeMapper.selectPage(new Page<EmployeeDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);
        if(entityDOPages!=null && entityDOPages.getSize() > 0) {
            Page<EmployeeVO> entityVOPage = BeanUtil.convertPage(entityDOPages, EmployeeVO.class);
            List<EmployeeDO> entityDOList = entityDOPages.getRecords();

            List<DepartmentDO> departmentDOList = departmentMapper.selectList(new LambdaQueryWrapper<DepartmentDO>().eq(DepartmentDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue()));
            Map<Long, String> departmentNameMaps = Collections3.isNotEmpty(departmentDOList) ? departmentDOList.parallelStream().collect(Collectors.toMap(DepartmentDO::getId, DepartmentDO::getName, (o, n) -> o)) : null;
            List<OrgPositionDO> orgPositionDOList = orgPositionMapper.selectList(new LambdaQueryWrapper<OrgPositionDO>().eq(OrgPositionDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue()));
            Map<Long, String> orgPositionNameMaps = Collections3.isNotEmpty(orgPositionDOList) ? orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getName, (o, n) -> o)) : null;
            Map<Long, Long> orgPositionJobMaps = Collections3.isNotEmpty(orgPositionDOList)?orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getJobId, (o, n) -> o)):null;

            List<EmployeeVO> resultVOList = entityDOList.stream().map(s -> {
                EmployeeVO entityVO = BeanUtil.convertBean(s, EmployeeVO.class);
                entityVO.setDepartmentName(departmentNameMaps!=null?departmentNameMaps.get(s.getDepartmentId()):"");
                entityVO.setPositionName(orgPositionNameMaps!=null?orgPositionNameMaps.get(s.getPositionId()):"");
                entityVO.setJobId(orgPositionJobMaps!=null?orgPositionJobMaps.get(s.getPositionId()):null);
                entityVO.setStatusDesc(EmployeeStatusEnum.getDescByCode(s.getStatus()));
                entityVO.setGenderDesc(SexEnum.getDescByCode(s.getGender()));
                return entityVO;
            }).collect(Collectors.toList());
            entityVOPage.setRecords(resultVOList);
            return entityVOPage;
        }
        return new Page<>();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(EmployeeParam param) {
        ParamCheckUtils.stringTrim(param);
        this.checkUnique(param);
        EmployeeDO EmployeeDO = BeanUtil.convertBean(param, EmployeeDO.class);
        EmployeeDO.setCreateBy(UserUtils.getUserId());
        EmployeeDO.setCreateTime(LocalDateTime.now());
        EmployeeDO.setModifyTime(LocalDateTime.now());
        return employeeMapper.insert(EmployeeDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean modify(EmployeeParam param) {
        ParamCheckUtils.stringTrim(param);
        this.checkUnique(param);
        EmployeeDO EmployeeDO = BeanUtil.convertBean(param, EmployeeDO.class);
        EmployeeDO.setModifyBy(UserUtils.getUserId());
        EmployeeDO.setModifyTime(LocalDateTime.now());
        return employeeMapper.updateById(EmployeeDO) > 0;
    }

    @Override
    public EmployeeVO view(Long id) {
        EmployeeDO entityDO = employeeMapper.selectById(id);
        if(entityDO == null) return new EmployeeVO();
        List<DepartmentDO> departmentDOList = departmentMapper.selectList(new LambdaQueryWrapper<DepartmentDO>().eq(DepartmentDO::getPublishStatus,PublishStatusEnum.ENABLE.getValue()));
        Map<Long, String> departmentNameMaps = Collections3.isNotEmpty(departmentDOList)?departmentDOList.parallelStream().collect(Collectors.toMap(DepartmentDO::getId, DepartmentDO::getName, (o, n) -> o)):null;

        List<OrgPositionDO> orgPositionDOList = orgPositionMapper.selectList(new LambdaQueryWrapper<OrgPositionDO>().eq(OrgPositionDO::getPublishStatus,PublishStatusEnum.ENABLE.getValue()));
        Map<Long, String> orgPositionNameMaps = Collections3.isNotEmpty(orgPositionDOList)?orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getName, (o, n) -> o)):null;
        Map<Long, Long> orgPositionJobMaps = Collections3.isNotEmpty(orgPositionDOList)?orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getJobId, (o, n) -> o)):null;

        EmployeeVO entityVO = BeanUtil.convertBeanByJson(entityDO, EmployeeVO.class);
        entityVO.setDepartmentName(departmentNameMaps!=null?departmentNameMaps.get(entityDO.getDepartmentId()):"");
        entityVO.setPositionName(orgPositionNameMaps!=null?orgPositionNameMaps.get(entityDO.getPositionId()):"");
        entityVO.setJobId(orgPositionJobMaps!=null?orgPositionJobMaps.get(entityDO.getPositionId()):null);
        entityVO.setGenderDesc(SexEnum.getDescByCode(entityDO.getGender()));
        entityVO.setStatusDesc(EmployeeStatusEnum.getDescByCode(entityDO.getStatus()));
        return entityVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeStatus(Long id, Integer status) {
        EmployeeDO EmployeeDO = employeeMapper.selectById(id);

        EmployeeDO.setStatus(status);
        EmployeeDO.setModifyBy(UserUtils.getUserId());
        EmployeeDO.setModifyTime(LocalDateTime.now());
        return employeeMapper.updateById(EmployeeDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean del(Long id) {
        EmployeeDO EmployeeDO = employeeMapper.selectById(id);
        if (EmployeeDO == null) {
            return true;
        }
        PublishStatusEnum.statusCheckException(EmployeeDO.getStatus());
        //删除会员偏好关系表数据
        return employeeMapper.deleteById(id) > 0;
    }

    @Override
    public List<EmployeeDTO> feignQueryEmployeeList(EmployeeFeignQuery query){
        List<EmployeeDTO> resultVOS = new ArrayList<>();
        List<EmployeeDO> entityDOS = employeeMapper.selectList(new LambdaQueryWrapper<EmployeeDO>()
                .eq(query.getId()!=null ,EmployeeDO::getId, query.getId())
                .in(Collections3.isNotEmpty(query.getIds()), EmployeeDO::getId, query.getIds())
                .eq(query.getDepartmentId()!=null ,EmployeeDO::getDepartmentId, query.getDepartmentId())
                .eq(query.getGender()!=null ,EmployeeDO::getGender, query.getGender())
                .eq(StringUtils.isNotEmpty(query.getCode()),EmployeeDO::getCode, query.getCode())
                .like(StringUtils.isNotEmpty(query.getName()),EmployeeDO::getName, query.getName())
                .eq(query.getStatus()!=null ,EmployeeDO::getStatus, query.getStatus())
                .orderByDesc(EmployeeDO::getCreateTime));
        if(Collections3.isNotEmpty(entityDOS)) {
            List<OrgPositionDO> orgPositionDOList = orgPositionMapper.selectList(new LambdaQueryWrapper<OrgPositionDO>().eq(OrgPositionDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue()));
            Map<Long, Long> orgPositionJobMaps = Collections3.isNotEmpty(orgPositionDOList) ? orgPositionDOList.parallelStream().collect(Collectors.toMap(OrgPositionDO::getId, OrgPositionDO::getJobId, (o, n) -> o)) : null;

            resultVOS = entityDOS.stream().map(s -> {
                EmployeeDTO entityDTO = BeanUtil.convertBean(s, EmployeeDTO.class);
                entityDTO.setJobId(orgPositionJobMaps != null ? orgPositionJobMaps.get(s.getPositionId()) : null);
                return entityDTO;
            }).collect(Collectors.toList());
        }
        return resultVOS;
    }

    @Override
    public SimpleEmployeeDTO feignQueryEmployee(Long employeeId) {
        EmployeeDO entityDO = employeeMapper.selectById(employeeId);
        if(entityDO == null) return new SimpleEmployeeDTO();

        List<OrgPositionDO> orgPositionDOS = orgPositionMapper.selectList(new LambdaQueryWrapper<OrgPositionDO>()
                .eq(OrgPositionDO::getPublishStatus,PublishStatusEnum.ENABLE.getValue())
                .eq(OrgPositionDO::getDepartmentId, entityDO.getDepartmentId())
        );
        List<Long> positionIds = Collections3.isNotEmpty(orgPositionDOS)?orgPositionDOS.stream().map(OrgPositionDO::getId).collect(Collectors.toList()):Collections3.emptyList();

        SimpleEmployeeDTO entityVO = BeanUtil.convertBeanByJson(entityDO, SimpleEmployeeDTO.class);
        entityVO.setPositionId(positionIds);
        return entityVO;
    }
    /**
     * 校验唯一性
     *
     * @param param
     */
    public void checkUnique(EmployeeParam param) {
        if (param == null) {
            throw new BusinessException("当前职位数据不存在!");
        }
        //code name确保等级唯一性
        LambdaQueryWrapper<EmployeeDO> queryWrapper = new LambdaQueryWrapper<EmployeeDO>()
                .ne(param.getId() != null, EmployeeDO::getId, param.getId())
                .eq(EmployeeDO::getName, param.getName());
        List<EmployeeDO> dos = employeeMapper.selectList(queryWrapper);
        if (Collections3.isNotEmpty(dos)) {
            throw new BusinessException("已经存在同名的职位!");
        }
    }

    private List<Long> getAllDepartmentIdsByPId(Long parentId){
        List<Long> departmentIdS = new ArrayList<>();
        departmentIdS.add(parentId);
        List<DepartmentDO> allDepartmentList = departmentMapper.selectList(new LambdaQueryWrapper<>(DepartmentDO.class).eq(DepartmentDO::getPublishStatus,PublishStatusEnum.ENABLE.getValue()));
        List<DepartmentTreeVO> allDepartmentTrees = JsonUtils.jsonToList(allDepartmentList, DepartmentTreeVO.class);
        List<Long> result = new ArrayList<>();
        TreeFastUtils.selectLongCidByPid(result, allDepartmentTrees, departmentIdS);
        result.addAll(departmentIdS);
        return result;
    }

    @Override
    public List<EmployeeStatusVO> employeeStatusList() {
        List<EmployeeStatusVO> result = new ArrayList<>();
        EmployeeStatusVO statusVO = null;
        for (EmployeeStatusEnum application : EmployeeStatusEnum.values()) {
            statusVO = new EmployeeStatusVO();
            statusVO.setCode(application.getCode());
            statusVO.setDesc(application.getDesc());
            result.add(statusVO);
        }
        return result;
    }

}